package com.xyh.builder;

import com.xyh.bean.Constants;
import com.xyh.bean.FieldInfo;
import com.xyh.bean.TableInfo;
import com.xyh.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BuilderMapperXml {
    private static final Logger logger = LoggerFactory.getLogger(BuilderMapperXml.class);
    private static final String BASE_COLUMN_LIST = "base_column_list";
    private static final String BASE_RESULT_MAP = "base_result_map";
    private static final String BASE_QUERY_CONDITION = "base_query_condition";
    private static final String BASE_QUERY_CONDITION_EXTEND = "base_query_condition_extend";
    private static final String QUERY_CONDITION = "query_condition";

    public static void execute(TableInfo tableInfo) {
        // 1. 创建输出目录
        File mapperXmlDir = new File(Constants.PATH_MAPPER_XML);
        if (!mapperXmlDir.exists() && !mapperXmlDir.mkdirs()) {
            logger.error("创建mapperXml目录失败: {}", Constants.PATH_MAPPER_XML);
            return;
        }

        // 2. 准备输出文件
        File poFile = new File(mapperXmlDir, tableInfo.getBeanName() + Constants.SUFFIX_MAPPER + ".xml");

        try (BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(poFile), StandardCharsets.UTF_8))) {

            // 3. 生成XML文件内容
            // 3.1 写XML头
            bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
            bw.write("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" ");
            bw.write("\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n");

            // 3.2 写mapper命名空间
            String namespace = Constants.PACKAGE_MAPPER + "." + tableInfo.getBeanName() + Constants.SUFFIX_MAPPER;
            bw.write("<mapper namespace=\"" + namespace + "\">\n\n");

            // 3.3 生成ResultMap
            generateResultMap(bw, tableInfo);

            //3.4 生成通用查询列
            generateSelectColumns(bw, tableInfo);
            //3.5 生成通用查询条件
            generateQueryCondition(bw, tableInfo);
            //3.6 生成扩展查询条件
            generateExtendQueryCondition(bw, tableInfo);
            //3.7 包含通用查询条件
            generateIncludeConditions(bw,tableInfo);
            //3.8 查询列表
            generateSelectList(bw, tableInfo);
            //3.9 查询列表总数
            generateSelectListCount(bw, tableInfo);
            //3.10 插入
            generateInsert(bw, tableInfo);
            //3.11 插入或更新
            generateInsertOrUpdate(bw, tableInfo);
            //3.12 批量插入
            generateBatchInsert(bw, tableInfo);
            //3.13 批量新增修改
            generateBatchInsertOrUpdate(bw, tableInfo);
            //3.14 根据主键CRUD
            generateCommonCRUD(bw, tableInfo);
            //3.15 多表关联查询
            generateMultiTableQuery(bw, tableInfo);
            // 3. 关闭根节点
            bw.write("</mapper>");
            bw.flush();

            logger.info("生成mapperXml成功: {}", poFile.getAbsolutePath());
        } catch (Exception e) {
            logger.error("生成mapperXml失败: 表名={}", tableInfo.getTableName(), e);
        }
    }

    private static void generateCommonCRUD(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        Set<String> keyFieldNameSet = new HashSet<>();
        for (Map.Entry<String, List<FieldInfo>> entry :tableInfo.getKeyIndexMap().entrySet()) {
            List<FieldInfo> keyFieldList = entry.getValue();
            Set<FieldInfo> keyFieldSet = new HashSet<>(keyFieldList);
            Integer index = 0;
            StringBuffer methodName = new StringBuffer();
            StringBuffer methodParams = new StringBuffer("WHERE ");
            for (FieldInfo fieldInfo : keyFieldList) {
                index++;
                methodName.append(StringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName()));
                if(index<keyFieldList.size()){
                    methodName.append("And");

                }
                methodParams.append(fieldInfo.getFieldName() +" = #{" + fieldInfo.getPropertyName() +"} ");
                if(index<keyFieldList.size()){
                    methodParams.append("AND");
                }
                keyFieldNameSet.add(fieldInfo.getPropertyName());
            }

            bw.write("\n\t<!--根据"+methodName+"查询-->\n");
            bw.write("\t<select id=\"selectBy"+methodName+"\" resultMap=\""+ BASE_RESULT_MAP +"\" >\n");
            bw.write("\t\tSELECT\n");
            bw.write("\t\t<include refid=\""+ BASE_COLUMN_LIST +"\"/>\n");
            bw.write("\t\tFROM " + tableInfo.getTableName() + "\n");
            bw.write("\t\t"+methodParams.toString() +"\n");
            bw.write("\t</select>\n");


            bw.write("\n\t<!--根据"+methodName+"删除-->\n");
            bw.write("\t<delete id=\"deleteBy"+ methodName +"\">\n");
            bw.write("\t\tDELETE FROM " + tableInfo.getTableName() + "\n");
            bw.write("\t\t"+methodParams.toString() +"\n");
            bw.write("\t</delete>\n");


            bw.write("\n\t<!--根据"+methodName+"修改-->\n");
            bw.write("\t<update id=\"updateBy"+ methodName +"\">\n");
            bw.write("\t\tUPDATE " + tableInfo.getTableName() + "\n");
            bw.write("\t\t<set>\n");
            for (FieldInfo field : tableInfo.getFieldList()) {
                //跳过主键(我们一般不修改主键)
                if(keyFieldSet.contains(field)){
                    continue;
                }
                bw.write("\t\t\t<if test=\"bean." + field.getPropertyName() + " != null\">\n");
                bw.write("\t\t\t\t" + field.getFieldName() + " = #{bean." + field.getPropertyName() + "},\n");
                bw.write("\t\t\t</if>\n");
            }
            bw.write("\t\t</set>\n");
            bw.write("\t\t"+methodParams.toString() +"\n");
            bw.write("\t</update>\n");

        }
        //根据id删除
        for (FieldInfo fieldInfo : tableInfo.getFieldList()) {
            if(!keyFieldNameSet.contains(fieldInfo.getPropertyName()) && fieldInfo.getPropertyName().toLowerCase().endsWith("id")){
                bw.write("\n\t<!--根据"+fieldInfo.getPropertyName()+"删除-->\n");
                bw.write("\t<delete id=\"deleteBy"+ StringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName()) +"\">\n");
                bw.write("\t\tDELETE FROM " + tableInfo.getTableName() + "\n");
                bw.write("\t\t WHERE "+fieldInfo.getFieldName() +" = #{" + fieldInfo.getPropertyName() +"}\n");
                bw.write("\t</delete>\n");
            }
        }


        // 新增通用条件删除
        bw.write("\n\t<!--根据查询条件删除-->\n");
        bw.write("\t<delete id=\"deleteByParams\">\n");
        bw.write("\t\tDELETE FROM " + tableInfo.getTableName() + "\n");
        bw.write("\t\t<include refid=\""+ QUERY_CONDITION+"\"/>\n");
        bw.write("\t</delete>\n");
    }

    private static void generateMultiTableQuery(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        // 多表关联查询
        bw.write("\n\t<!-- 多表关联查询 -->\n");
        bw.write("\t<select id=\"selectJoin\" resultType=\"java.util.Map\">\n");
        bw.write("\t\tSELECT\n");
        bw.write("\t\t${selectColumns}\n");
        bw.write("\t\tFROM ${joinTables}\n");
        bw.write("\t\t<if test=\"joinConditions != null and joinConditions != ''\">\n");
        bw.write("\t\t\t${joinConditions}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t\t<if test=\"whereConditions != null and whereConditions != ''\">\n");
        bw.write("\t\t\tWHERE ${whereConditions}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t</select>\n");

        // 多表关联查询结果总数
        bw.write("\n\t<!-- 多表关联查询结果总数 -->\n");
        bw.write("\t<select id=\"selectJoinCount\" resultType=\"java.lang.Long\">\n");
        bw.write("\t\tSELECT COUNT(*) \n");
        bw.write("\t\tFROM ${joinTables}\n");
        bw.write("\t\t<if test=\"joinConditions != null and joinConditions != ''\">\n");
        bw.write("\t\t\t${joinConditions}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t\t<if test=\"whereConditions != null and whereConditions != ''\">\n");
        bw.write("\t\t\tWHERE ${whereConditions}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t</select>\n");

        // 多表关联分页查询
        bw.write("\n\t<!-- 多表关联分页查询 -->\n");
        bw.write("\t<select id=\"selectJoinPage\" resultType=\"java.util.Map\">\n");
        bw.write("\t\tSELECT\n");
        bw.write("\t\t${selectColumns}\n");
        bw.write("\t\tFROM ${joinTables}\n");
        bw.write("\t\t<if test=\"joinConditions != null and joinConditions != ''\">\n");
        bw.write("\t\t\t${joinConditions}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t\t<if test=\"whereConditions != null and whereConditions != ''\">\n");
        bw.write("\t\t\tWHERE ${whereConditions}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t\t<if test=\"orderBy != null and orderBy != ''\">\n");
        bw.write("\t\t\tORDER BY ${orderBy}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t\t<if test=\"offset != null and limit != null\">\n");
        bw.write("\t\t\tLIMIT #{offset}, #{limit}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t</select>\n");
    }

    private static void generateBatchInsertOrUpdate(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\n\t<!-- 批量插入或修改（推荐单批次数据量控制在500条以内） -->\n");
        bw.write("\t<insert id=\"insertOrUpdateBatch\" parameterType=\""+Constants.PACKAGE_PO + "." + tableInfo.getBeanName()+"\">\n"); // 修正参数类型为List
        bw.write("\t\tINSERT INTO " + tableInfo.getTableName() + "\n");

        // 字段列表（跳过自增主键）
        bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            bw.write("\t\t\t" + field.getFieldName() + ",\t<!-- " + field.getComment() + " -->\n");
        }
        bw.write("\t\t</trim>\n");

        // 值列表
        bw.write("\t\tVALUES\n");
        bw.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\">\n");
        bw.write("\t\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            bw.write("\t\t\t\t#{item." + field.getPropertyName() + "},\n");
        }
        bw.write("\t\t\t</trim>\n");
        bw.write("\t\t</foreach>\n");

        // 冲突更新逻辑（修复逗号问题）
        bw.write("\t\tON DUPLICATE KEY UPDATE\n");
        bw.write("\t\t<trim suffixOverrides=\",\">\n");  // 新增trim处理末尾逗号
        for (FieldInfo field : tableInfo.getFieldList()) {
            if (field.getAutoIncrement() != null && field.getAutoIncrement()) {
                continue;
            }
            bw.write("\t\t\t" + field.getFieldName() + " = VALUES(" + field.getFieldName() + "),\n");
        }
        bw.write("\t\t</trim>\n");  // 关闭trim标签
        bw.write("\t</insert>\n");
    }


    private static void generateBatchInsert(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\n\t<!-- 批量插入（推荐单批次数据量控制在500条以内） -->\n");
        bw.write("\t<insert id=\"insertBatch\" parameterType=\"" + Constants.PACKAGE_PO + "." + tableInfo.getBeanName() + "\">\n");
        bw.write("\t\tINSERT INTO " + tableInfo.getTableName() + "\n");

        // 字段列表优化：跳过自增主键，添加注释说明
        bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            if (field.getAutoIncrement() != null && field.getAutoIncrement()) {
                continue;
            }
            bw.write("\t\t\t" + field.getFieldName() + ",\t<!-- " + field.getComment() + " -->\n");
        }
        bw.write("\t\t</trim>\n");

        // 值列表优化：统一字段顺序，避免逗号残留
        bw.write("\t\tVALUES\n");
        bw.write("\t\t<foreach collection=\"list\" item=\"item\" separator=\",\">\n");
        bw.write("\t\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            if (field.getAutoIncrement() != null && field.getAutoIncrement()) {
                continue;
            }
            bw.write("\t\t\t\t#{item." + field.getPropertyName() + "},\n");
        }
        bw.write("\t\t\t</trim>\n");
        bw.write("\t\t</foreach>\n");
        bw.write("\t</insert>\n");
    }

    private static void generateInsertOrUpdate(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\n\t<!-- 插入或更新(自动处理唯一键冲突) -->\n");

        //useGeneratedKeys=\"true\" keyProperty=\""+primaryKey+"\"
        bw.write("\t<insert id=\"insertOrUpdate\" parameterType=\"" + Constants.PACKAGE_PO + "." + tableInfo.getBeanName() + "\" useGeneratedKeys=\"true\" >\n");

        // INSERT 表名
        bw.write("\t\tINSERT INTO " + tableInfo.getTableName() + "\n");

        // 动态生成字段列表
        bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            bw.write("\t\t\t<if test=\"bean." + field.getPropertyName() + " != null\">\n");
            bw.write("\t\t\t\t" + field.getFieldName() + ",\n");
            bw.write("\t\t\t</if>\n");
        }
        bw.write("\t\t</trim>\n\n");

        // 动态生成 VALUES 列表
        bw.write("\t\t<trim prefix=\"VALUES (\" suffix=\")\" suffixOverrides=\",\">\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            bw.write("\t\t\t<if test=\"bean." + field.getPropertyName() + " != null\">\n");
            bw.write("\t\t\t\t#{bean." + field.getPropertyName() + "},\n");
            bw.write("\t\t\t</if>\n");
        }
        bw.write("\t\t</trim>\n\n");

        // ON DUPLICATE KEY UPDATE 部分优化点：
        bw.write("\t\tON DUPLICATE KEY UPDATE\n");
        bw.write("\t\t<trim suffixOverrides=\",\">\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            // 跳过自增主键（通常无需更新）
            if (field.getAutoIncrement() != null && field.getAutoIncrement()) {
                continue;
            }

            bw.write("\t\t\t<if test=\"bean." + field.getPropertyName() + " != null\">\n");
            // 关键优化：使用 VALUES() 函数引用插入值，避免硬编码字段名
            bw.write("\t\t\t\t" + field.getFieldName() + " = VALUES(" + field.getFieldName() + "),\n");
            bw.write("\t\t\t</if>\n");
        }
        bw.write("\t\t</trim>\n");

        bw.write("\t</insert>\n");
    }

    private static void generateIncludeConditions(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\t<!--包含通用查询条件-->\n");
        bw.write("\t<sql id=\""+ QUERY_CONDITION+"\">\n");
        bw.write("\t\t<where>\n");
        bw.write("\t\t\t<include refid = \""+ BASE_QUERY_CONDITION+"\"/>\n");
        bw.write("\t\t\t<include refid = \""+ BASE_QUERY_CONDITION_EXTEND+"\"/>\n");
        bw.write("\t\t</where>\n");
        bw.write("\t</sql>\n\n");
    }

    private static void generateInsert(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\n\t<!--插入-->\n");

        bw.write("\t<insert id=\"insertEntity\" parameterType=\"" + Constants.PACKAGE_PO + "." + tableInfo.getBeanName() + "\" useGeneratedKeys=\"true\">\n");
        // 处理自增主键
        FieldInfo autoIncrementField = null;
        for (FieldInfo field : tableInfo.getFieldList()) {
            if (field.getAutoIncrement() != null && field.getAutoIncrement()) {
                autoIncrementField = field;
                break;
            }
        }
        if (autoIncrementField != null) {
            bw.write("\t\t<selectKey keyProperty=\"bean." + autoIncrementField.getPropertyName() + "\" resultType=\""
                    + autoIncrementField.getJavaType() + "\" order=\"AFTER\">\n");
            bw.write("\t\t\tSELECT LAST_INSERT_ID()\n");
            bw.write("\t\t</selectKey>\n");
        }

        // 插入主体
        bw.write("\t\tINSERT INTO " + tableInfo.getTableName() + "\n"); // 补全表名

        // 字段列表
        bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            // 跳过自增字段
            if (field.getAutoIncrement() != null && field.getAutoIncrement()) {
                continue;
            }

            bw.write("\t\t\t<if test=\"bean." + field.getPropertyName() + " != null\">\n");
            bw.write("\t\t\t\t" + field.getFieldName() + ",\n");
            bw.write("\t\t\t</if>\n");
        }
        bw.write("\t\t</trim>\n");

        // 值列表
        bw.write("\t\tVALUES\n"); // 补全VALUES关键字
        bw.write("\t\t<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            // 跳过自增字段
            if (field.getAutoIncrement() != null && field.getAutoIncrement()) {
                continue;
            }

            bw.write("\t\t\t<if test=\"bean." + field.getPropertyName() + " != null\">\n");
            bw.write("\t\t\t\t#{bean." + field.getPropertyName() + "},\n");
            bw.write("\t\t\t</if>\n");
        }
        bw.write("\t\t</trim>\n");

        bw.write("\t</insert>\n");
    }

    private static String detectPrimaryKey(List<FieldInfo> fieldList,
                                           Map<String, List<FieldInfo>> keyIndexMap) {
        for (Map.Entry<String, List<FieldInfo>> entry : keyIndexMap.entrySet()) {
            if ("PRIMARY".equalsIgnoreCase(entry.getKey())) {
                return entry.getValue().get(0).getFieldName();
            }
        }

        return fieldList.stream()
                .filter(f -> f.getFieldName().toLowerCase().endsWith("id"))
                .findFirst()
                .map(FieldInfo::getFieldName)
                .orElse("");
    }

    private static void generateSelectListCount(BufferedWriter bw, TableInfo tableInfo) throws IOException {
    /*
    	<!--查询数量-->
	<select id="selectCount" resultType="java.lang.Integer">
		select count(1)
		from biz_order
		<include refid="query_condition"/>
	</select>
    **/
        bw.write("\n\t<!--查询数量-->\n");
        bw.write("\t<select id=\"selectCountByCollection\" resultType=\"java.lang.Long\">\n");
        bw.write("\t\tselect count(1)\n");
        bw.write("\t\tfrom " + tableInfo.getTableName() + "\n");
        bw.write("\t\t<include refid=\""+ QUERY_CONDITION+"\"/>\n");
        bw.write("\t</select>\n");

    }

    private static void generateSelectList(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\t<!--查询列表-->\n");
        bw.write("\t<select id=\"selectByParams\" resultMap=\""+ BASE_RESULT_MAP+"\">\n");
        bw.write("\t\tselect\n");
        bw.write("\t\t<include refid=\""+ BASE_COLUMN_LIST+"\"/>\n");
        bw.write("\t\tfrom " + tableInfo.getTableName() + "\n");
        bw.write("\t\t<include refid=\""+ QUERY_CONDITION+"\"/>\n");

        bw.write("\t\t<if test=\"query.orderBy != null\">\n");
        bw.write("\t\t\torder by ${query.orderBy}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t\t<if test=\"query.simplePage != null\">\n");
        bw.write("\t\t\tlimit #{query.simplePage.offset},#{query.simplePage.pageSize}\n");
        bw.write("\t\t</if>\n");
        bw.write("\t</select>\n");
    }

    private static void generateExtendQueryCondition(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\t<!--扩展查询条件-->\n");
        bw.write("\t<sql id=\""+ BASE_QUERY_CONDITION_EXTEND+"\">\n");
//        bw.write("\t\t<where>\n");
        for (FieldInfo field : tableInfo.getExtendFieldList()) {
            bw.write("\t\t<if test=\"query." + field.getPropertyName() + " != null");
            bw.write(" and query." + field.getPropertyName() + " != ''");
            bw.write("\">\n");
            if(Constants.SQL_STRING_TYPES.contains(field.getSqlType())){
                bw.write("\t\t\tand " + field.getFieldName() + "\n\t\t\tlike concat('%',#{query." + field.getPropertyName() + "},'%')\n");
            } else if (Constants.SQL_DATE_TIMES_TYPES.contains(field.getSqlType())||
                        Constants.SQL_DATE_TYPES.contains(field.getSqlType())
            ) {
                if(field.getPropertyName().endsWith( Constants.SUFFIX_BEAN_PARAM_TIME_START)){
                    bw.write("\t\t\t<![CDATA[ and "+field.getFieldName()+" >= str_to_date(#{query."+field.getPropertyName()+"} ,'%Y-%m-%d')]]>\n");
                }else if(field.getPropertyName().endsWith( Constants.SUFFIX_BEAN_PARAM_TIME_END)){
                    bw.write("\t\t\t<![CDATA[ and "+field.getFieldName()+" < date_sub(str_to_date(#{query."+field.getPropertyName()+"} ,'%Y-%m-%d'),interval -1 day)]]>\n");
                }
            } else{
                bw.write("\t\t\tand " + field.getFieldName() + " = #{query." + field.getPropertyName() + "}\n");
            }

            bw.write("\t\t</if>\n");
        }
//        bw.write("\t\t</where>\n");
        bw.write("\t</sql>\n\n");
    }

    private static void generateQueryCondition(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        bw.write("\t<!--通用查询条件-->\n");
        bw.write("\t<sql id=\""+ BASE_QUERY_CONDITION+"\">\n");
//        bw.write("\t\t<where>\n");
        for (FieldInfo field : tableInfo.getFieldList()) {
            bw.write("\t\t<if test=\"query." + field.getPropertyName() + " != null");
            if(Constants.SQL_STRING_TYPES.contains(field.getSqlType())){
                bw.write(" and query." + field.getPropertyName() + " != ''");
            }
            bw.write("\">\n");
            bw.write("\t\t\tand " + field.getFieldName() + " = #{query." + field.getPropertyName() + "}\n");
            bw.write("\t\t</if>\n");
        }
//        bw.write("\t\t</where>\n");
        bw.write("\t</sql>\n\n");
    }

    /**
     * 生成通用查询列的SQL片段
     * 该方法根据表信息（TableInfo）中的字段列表，动态生成一个包含所有字段的SQL片段，
     * 用于在MyBatis的XML映射文件中作为可重用的SQL部分
     *
     * @param bw 缓冲写入器，用于将生成的SQL片段写入到文件中
     * @param tableInfo 表信息对象，包含表的字段列表等信息
     * @throws IOException 如果在写入过程中发生I/O错误
     */
    private static void generateSelectColumns(BufferedWriter bw, TableInfo tableInfo) throws IOException {
        // 写入注释，说明接下来是通用查询列的部分
        bw.write("\t<!--通用查询列-->\n");

        // 写入SQL片段的开始标签，id为"base_column_list"
        bw.write("\t<sql id=\""+ BASE_COLUMN_LIST+"\">\n");
        StringBuilder sb = new StringBuilder("\t\t");
        // 遍历表中的所有字段，生成字段名列表
        int index = 0;
        for (FieldInfo field : tableInfo.getFieldList()) {
            // 写入字段名，并换行
            sb.append(field.getFieldName());
            if(++index < tableInfo.getFieldList().size()){
                sb.append(",");
            }
        }
        bw.write(sb.toString());
        bw.newLine();
        // 写入SQL片段的结束标签
        bw.write("\t</sql>\n\n");
    }

    /**
     * 生成ResultMap映射配置
     * @param bw 文件写入器
     * @param tableInfo 表信息
     */
    private static void generateResultMap(BufferedWriter bw, TableInfo tableInfo) throws Exception {
        // 获取主键字段名（优先通过索引查找，找不到则查找以id结尾的字段）
        String primaryKey = "";
        for (Map.Entry<String, List<FieldInfo>> entry : tableInfo.getKeyIndexMap().entrySet()) {
            if ("PRIMARY".equalsIgnoreCase(entry.getKey())) {
                primaryKey = entry.getValue().get(0).getFieldName();
                break;
            }
        }
        if (primaryKey.isEmpty()) {
            for (FieldInfo field : tableInfo.getFieldList()) {
                if (field.getFieldName().toLowerCase().endsWith("id")) {
                    primaryKey = field.getFieldName();
                    break;
                }
            }
        }

        // 开始编写resultMap
        bw.write("\t<!-- 实体类与数据库字段映射配置 -->\n");
//        String resultMapId = tableInfo.getBeanName() + "ResultMap";
        String poClass = Constants.PACKAGE_PO + "." + tableInfo.getBeanName();
        bw.write("\t<resultMap id=\"" + BASE_RESULT_MAP + "\" type=\"" + poClass + "\">\n");

        // 先处理主键字段
        for (FieldInfo field : tableInfo.getFieldList()) {
            if (field.getFieldName().equalsIgnoreCase(primaryKey)) {
                writeFieldMapping(bw, field, true);
            }
        }

        // 处理普通字段
        for (FieldInfo field : tableInfo.getFieldList()) {
            if (!field.getFieldName().equalsIgnoreCase(primaryKey)) {
                writeFieldMapping(bw, field, false);
            }
        }

        bw.write("\t</resultMap>\n\n");
    }

    /**
     * 写入字段映射配置
     * @param bw 文件写入器
     * @param field 字段信息
     * @param isPrimary 是否主键字段
     */
    private static void writeFieldMapping(BufferedWriter bw, FieldInfo field, boolean isPrimary) throws Exception {
        // 添加字段注释
        if (field.getComment() != null) {
            bw.write("\t\t<!-- " + field.getComment() + " -->\n");
        }

        // 生成映射标签
        String tagName = isPrimary ? "id" : "result";
        String line = String.format("\t\t<%s property=\"%s\" column=\"%s\" />",
                tagName, field.getPropertyName(), field.getFieldName());
        bw.write(line + "\n");
    }
}